# There are three views for this app: Rings, Events, and Competitors
# With no arguments, each view will default to displaying a list of all items
# With arguments, the view will display information about the selected item

import re
import copy
from django.http import HttpResponse
from django.shortcuts import render
from django.shortcuts import redirect
from django.core.exceptions import ObjectDoesNotExist
from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_headers
from django.db.models import Q
from models import Ring
from models import Competitor
from models import Event
from models import EventType
from models import Level
from models import AgeGroup
from models import Gender
from models import Placing
from models import EVENT_CATAGORIES
import datetime
import os
import csv
import zipfile
import json
from django import forms
from data import data_import

# Mobile UA Checker
# list of mobile User Agents
mobile_uas = [
	'w3c ','acs-','alav','alca','amoi','audi','avan','benq','bird','blac',
	'blaz','brew','cell','cldc','cmd-','dang','doco','eric','hipt','inno',
	'ipaq','java','jigs','kddi','keji','leno','lg-c','lg-d','lg-g','lge-',
	'maui','maxo','midp','mits','mmef','mobi','mot-','moto','mwbp','nec-',
	'newt','noki','oper','palm','pana','pant','phil','play','port','prox',
	'qwap','sage','sams','sany','sch-','sec-','send','seri','sgh-','shar',
	'sie-','siem','smal','smar','sony','sph-','symb','t-mo','teli','tim-',
	'tosh','tsm-','upg1','upsi','vk-v','voda','wap-','wapa','wapi','wapp',
	'wapr','webc','winw','winw','xda','xda-'
	]

mobile_ua_hints = [ 'SymbianOS', 'Opera Mini', 'iPhone' ]

def check_mobile_browser(request):
  """Super simple device detection, returns True for mobile devices"""
  mobile_browser = False
  if 'site' in request.COOKIES:
    if request.COOKIES['site'] == 'desktop':
      return False
    if request.COOKIES['site'] == 'mobile':
      return True
  ua = request.META['HTTP_USER_AGENT'].lower()[0:4]
  if 'force_mobile' in request.GET:
    mobile_browser = True
  if (ua in mobile_uas):
    mobile_browser = True
  else:
    for hint in mobile_ua_hints:
      if request.META['HTTP_USER_AGENT'].find(hint) > 0:
        mobile_browser = True
  return mobile_browser

# Sets a cookie to default to the mobile site
def set_mobile(request):
  url = request.GET['url'] or '/'
  response = redirect(url)
  response.set_cookie('site', 'mobile')
  return response

# Sets a cookie to default to the desktop site
def set_desktop(request):
  url = request.GET['url'] or '/'
  response = redirect(url)
  response.set_cookie('site', 'desktop')
  return response

# Calls are made through this to include default template stuff
def render_with_base(request, template, dictionary):
  response = {}
  if os.path.exists('updated.txt'):
    response['last_updated'] = datetime.datetime.fromtimestamp(os.path.getmtime('updated.txt'))
    if datetime.datetime.now() - response['last_updated'] < datetime.timedelta(minutes=5) :
      response['last_updated'] = datetime.datetime.now() - datetime.timedelta(minutes=5)
  dictionary.update(response)
  return render(request, template, dictionary)

def render_with_template(template, template_mobile=None):
  def _wrapper(fn):
    def _inner_wrapper(request, *args, **kwargs):
      result = fn(request, *args, **kwargs)
      result['url'] = request.path
      template_mobile = '%s_mobile.html' % template.replace('.html', '')
      if check_mobile_browser(request):
        return render_with_base(request, template_mobile, result)
      else:
        return render_with_base(request, template, result)
    return _inner_wrapper
  return _wrapper

# Rings
# http://scores.calwushu.org/rings   - List of rings
@vary_on_headers('User-Agent', 'Cookie')
@render_with_template('rings.html')
def rings(request):
  return _rings(request)

def _rings(request):
  """Returns a list of rings if no specific ring is selected."""
  response = {}
  # Get list of competitors for searching purposes.
  response['competitors_json'] = json.dumps(['%s %s' % (comp.first_name, comp.last_name)
      for comp in Competitor.objects.exclude(events=None)])
  rings = Ring.objects.all()
  rings_meta = []
  for ring in rings:
    unfinished_events = Event.objects.filter(ring=ring, completed=False, num_competitors__gt=0)
    meta_data = {
      'num_unfinished_events': len(unfinished_events),
    }
    if unfinished_events:
      meta_data['next_event'] = unfinished_events.order_by('order')[0]
    rings_meta.append((ring, meta_data))
  response['rings'] = rings_meta
  return response

# http://scores.calwushu.org/ring/1 - Displays info on ring 1
@vary_on_headers('User-Agent', 'Cookie')
@render_with_template('ring.html')
def ring(request, ring_number):
  """Display all current, previous, and future events"""
  response = {}
  response['competitors_json'] = json.dumps(['%s %s' % (comp.first_name, comp.last_name)
      for comp in Competitor.objects.exclude(events=None)])
  response['ring'] = Ring.objects.get(number=ring_number)
  response['current_events'] = Event.objects.filter(ring=response['ring'], ongoing=True, num_competitors__gt=0)
  response['previous_events'] = Event.objects.filter(ring=response['ring'],
      completed=True, ongoing=False, num_competitors__gt=0).order_by('order')
  response['future_events'] = Event.objects.filter(ring=response['ring'],
      completed=False, ongoing=False, num_competitors__gt=0).order_by('order')
  response.update(_rings(request))
  return response


# Events
# http://scores.calwushu.org/events        - List of events
# http://scores.calwushu.org/events/40     - List of levels
# http://scores.calwushu.org/events/40/I   - List of age groups
# http://scores.calwushu.org/events/40/I/Y - List of genders
@vary_on_headers('User-Agent', 'Cookie')
@render_with_template('events.html')
def events(request, event_code=None, level=None, age_group=None):
  return _events(request, event_code, level, age_group)

def _events(request, event_code=None, level=None, age_group=None):
  """Returns a list of events if no event is selected.  If a partial query is
  given, display a list of levels, age groups, and gender until a specific
  event shortcode can be found."""
  response = {
    'event_code': event_code,
    'level': level,
    'age_group': age_group,
    'is_event': True,
    'url': request.path
  }
  """
  response['all_events'] = {}
  for catagory, catagory_events in response['event_catagories']:
    for sub_catagory, sub_catagory_events in catagory_events:
      for event_details in sub_catagory_events:
        if len(event_details) > 2: continue
        event_id, event_name = event_details
        catatory_event_type = EventType.objects.get(code__startswith=str(event_id))
        event_details.append(catatory_event_type)
        event_details.append(len(Competitor.objects.filter(events__event_type=catatory_event_type)))
  """

  response['competitors_json'] = json.dumps(['%s %s' % (comp.first_name, comp.last_name)
      for comp in Competitor.objects.exclude(events=None)])

  # List events
  all_events = EventType.objects.all()
  response['events'] = [(_event, {
    'num_competitors': len(Competitor.objects.filter(events__event_type=_event))
  }) for _event in all_events]

  if event_code:
    # Have event code, we want the level
    event_type = EventType.objects.get(code__startswith=event_code)
    levels = []
    events = Event.objects.filter(event_type=event_type, num_competitors__gt=0)
    for event in events:
      levels.append(event.level.pk)
    response['event_code'] = event_code
    response['event_type'] = event_type
    response['levels'] = [(_level, {
      'num_competitors': len(Competitor.objects.filter(events__level=_level, events__event_type=event_type)),
      'is_active': _level.code == level,
    }) for _level in Level.objects.filter(pk__in=levels)]

  if level:
    # Have level, want age_groups
    age_groups = []
    for event in events.filter(level__code__startswith=level, num_competitors__gt=0):
      age_groups.append(event.age_group.pk)
    response['level_name'] = Level.objects.get(code__startswith=level).name
    response['age_groups'] = [(_age_group, {
      'num_competitors': len(Competitor.objects.filter(
          events__level__code=level, events__event_type=event_type,
          events__age_group=_age_group)),
      'is_active': _age_group.code == age_group,
    }) for _age_group in AgeGroup.objects.filter(pk__in=age_groups)]

  if age_group:
    # Have age group want gender
    genders = [event.gender.pk for event in events.filter(age_group__code__startswith=age_group,
        num_competitors__gt=0, level__code=level)]
    response['age_group_name'] = AgeGroup.objects.get(code__startswith=age_group, pk__in=age_groups).name
    gender_events = []
    for _gender in Gender.objects.filter(pk__in=genders):
      shortcode = '%s%s%s%s' % (
          level, _gender.code, age_group, event_type.code
      )
      shortcode = shortcode.replace(' ', '')
      gender_events.append((_gender, {
        'num_competitors': Event.objects.get(shortcode=shortcode).num_competitors
      }))
    response['genders'] = gender_events
  return response

# http://scores.calwushu.org/event/IYF40  - Event details
@vary_on_headers('User-Agent', 'Cookie')
@render_with_template('event.html')
def event(request, shortcode):
  """Display event detail."""
  response = {}
  response['competitors_json'] = json.dumps(['%s %s' % (comp.first_name, comp.last_name)
      for comp in Competitor.objects.exclude(events=None)])
  this_event = Event.objects.get(shortcode__iexact=shortcode)
  response['event'] = this_event
  response['event_order'] = len(Event.objects.filter(ring=this_event.ring,
      order__lt=this_event.order, completed=False))
  if this_event.completed:
    placings = Placing.objects.filter(event=this_event).order_by('place')
  else:
    placings = Placing.objects.filter(event=this_event).order_by('order')
  response['competitors'] = [placing.competitor for placing in placings]
  response['placings'] = [(placing, {
    'time_deduct': float(placing.time_deduct) / 100.0,
    'other_deduct': float(placing.other_deduct) / 100.0,
    'scores': [float(score) / 100.0 for score in placing.scores.split(',')]
  }) for placing in placings]
  if not check_mobile_browser(request):
    response.update(_events(
      request,
      this_event.event_type.code,
      this_event.level.code,
      this_event.age_group.code
    ))
    response['gender'] = this_event.gender.code
  return response

# Competitors
# http://scores.calwushu.org/competitors - List of competitors
@vary_on_headers('User-Agent', 'Cookie')
@render_with_template('competitors.html')
def competitors(request):
  """Returns a list of competitors if no competitor is selected. """
  response = {}
  response['competitors_json'] = json.dumps(['%s %s' % (comp.first_name, comp.last_name)
      for comp in Competitor.objects.exclude(events=None)])
  response['competitors'] = Competitor.objects.exclude(events=None).extra(
      select={'lower_first_name': 'lower(first_name)',
      'lower_last_name': 'lower(last_name)'}).order_by('lower_first_name', 'lower_last_name')
  response['is_comp'] = True
  return response

# http://scores.calwushu.org/competitor/Doe/John - Competitor details
@vary_on_headers('User-Agent', 'Cookie')
@render_with_template('competitor.html')
def competitor(request, last_name, first_name):
  """Displays competitor information"""
  response = {}
  response['competitors_json'] = json.dumps(['%s %s' % (comp.first_name, comp.last_name)
      for comp in Competitor.objects.exclude(events=None)])
  response['is_comp'] = True
  competitor = Competitor.objects.exclude(events=None).get(
      last_name__iexact=last_name, first_name__istartswith=first_name)
  response['competitor'] = competitor
  response['placings'] = Placing.objects.filter(competitor=response['competitor'])
  completed_events = []
  unfinished_events = []
  response['all_around_score'] = 0
  for event in competitor.events.all():
    if event.completed:
      try:
        placing = Placing.objects.get(event=event, competitor=competitor)
      except ObjectDoesNotExist:
        placing = None
      completed_events.append({
        'event': event,
        'placing': placing
      })
      if placing:
        if placing.place == 1:
          response['all_around_score'] += 3
        elif placing.place == 2:
          response['all_around_score'] += 2
        elif placing.place == 3:
          response['all_around_score'] += 1
    else:
      unfinished_events.append(event)
  response['completed_events'] = completed_events
  response['unfinished_events'] = []
  for unfinished_event in unfinished_events:
    # How many events are in front?
    unfinished_ring = unfinished_event.ring
    order = len(Event.objects.filter(ring=unfinished_ring,
        order__lt=unfinished_event.order, completed=False))
    response['unfinished_events'].append((unfinished_event, {
      'order': order
    }))
  return response

@vary_on_headers('User-Agent', 'Cookie')
def search(request):
  query = request.GET['query'] or ''
  query.replace(',', ' ')
  competitors = Competitor.objects.exclude(events=None)
  for word in query.split(' '):
    competitors = competitors.filter(Q(first_name__icontains=word) | Q(last_name__icontains=word))
  if competitors:
    if len(competitors) == 1:
      competitor = competitors.get()
      return redirect('/competitor/%s/%s' % (competitor.last_name, competitor.first_name))
  raise
  return redirect('/')
